import React, {useState, useCallback, memo} from "react";
import {Button, Card} from 'antd';

const CacheError = {
    Children: memo(() => {
        console.log('子组件重新渲染了')

        return (
            <div className={'flex-items-center'}>
                <h3>我是使用 react.memo 方法缓存的 子组件</h3>
            </div>

        )
    }),
    Parent: () => {
        console.log('父组件重新渲染了')
        const [count, setCount] = useState(0)
        const arr = [1, 2, 3]
        const fn = () => {
        }
        return (
            <div>
                <div>被缓存的子组件<span className={'label-red'}> 未使用父组件中的方法</span> 也会重新渲染执行</div>
                <div className={'flex-items-center'}>
                    <h3>我是父组件,当前count值为:{count};点击后父组件和子组件都重新执行了</h3>
                    <Button onClick={() => setCount(count + 1)}>父组件count:+1</Button>
                </div>
                {/**
                 问题:
                 传入 方法   fn都是函数局部作用域里 由于组件每次数据更新都会重新渲染数据   所以fn未做任何操作  也会引起函数 子组件更新
                 解决办法 :
                 fn 操作方法使用 useCallback 定义
                 */}
                <CacheError.Children fn={fn}/>
            </div>
        )
    }
}

const CacheSuccess = {
    Children: memo(() => {
        console.log('子组件重新渲染了')

        return (
            <div className={'flex-items-center'}>
                <h3>我是使用 react.memo 方法缓存的 子组件</h3>
            </div>

        )
    }),
    Parent: () => {
        console.log('父组件重新渲染了')
        const [count, setCount] = useState(0)
        const [isUpdate,setIsUpdate] = useState(false)

        {/**
          只有当  依赖项 isUpdate  值改变后  会返回一个新的回调函数  才会触发子组件的刷新
         **/}
        const fn = useCallback(() => {
        },[isUpdate])

        return (
            <div>
                <div>只有当 <span className={'label-red'}>依赖项 isUpdate  值改变后</span>  会返回一个新的回调函数  才会触发子组件的刷新</div>
                <div>
                    <h3>我是父组件,当前count值为:{count};点击后父组件和子组件都重新执行了</h3>
                    <Button onClick={() => setCount(count + 1)}>父组件count:+1</Button>
                    <Button onClick={() => setIsUpdate(!isUpdate)}>重新渲染子组件</Button>
                </div>
                {/**
                 问题:
                 传入 方法   fn都是函数局部作用域里 由于组件每次数据更新都会重新渲染数据   所以fn未做任何操作  也会引起函数 子组件更新
                 解决办法 :
                 fn 操作方法使用 useCallback 定义
                 */}
                <CacheSuccess.Children fn={fn}/>
            </div>
        )
    }
}


export default () => {
    return (
        <Card hoverable>
            <h1>useCallback的使用:</h1>
            <div>
                用于<span className={'definition-2'}>缓存</span>需要在组件中多次调用的回调 <span
                className={'definition-2'}> 函数</span>。
                它接受两个参数：回调函数和依赖数组。
                当依赖数组中的任何一个值发生变化时，useCallback将会返回一个新的回调函数，
                否则将会返回之前缓存的回调函数。
                这样可以避免在每次渲染时都重新生成回调函数，从而提高组件的性能
            </div>
            <div className={'module'} style={{marginTop: 10}}>
                <div>问题演示:</div>
                <CacheError.Parent/>
            </div>
            <div className={'module'} style={{marginTop: 10}}>
                <div>使用useCallback:</div>
                <CacheSuccess.Parent/>
            </div>
        </Card>
    )
}